package com.xmg.aop;

import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @description: 注解增强类
 * @Author: mazhongqing
 * @Date: 2021/3/31 16:57
 */
@Component
@Aspect
@Slf4j
public class PrintLogAspect {

    @Around(value = "@annotation(com.xmg.aop.PrintLog)")
    public Object handlerPrintLog(ProceedingJoinPoint joinPoint) throws NotFoundException {
        String clazzName = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Map<String,Object> nameAndArgs = getFieldsName(this.getClass(),clazzName,methodName,args);
        log.info("Enter class[{}] method[{}] params[{}]",clazzName,methodName,nameAndArgs);
        Object object = null;
        try {
            object = joinPoint.proceed();
        }catch (Throwable throwable){
            log.error("Process class[{}] method[{}] error [{}]",clazzName,methodName,throwable.getMessage());
        }
        log.info("End class[{}] method[{}]",clazzName,methodName);
        return object;

    }

    private Map<String,Object> getFieldsName(Class clazz,String clazzName,String methodName,Object[] args) throws NotFoundException {
        Map<String,Object> map = new HashMap<>();
        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(clazz);
        pool.insertClassPath(classPath);

        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if(attr==null){

        }
        int pos = Modifier.isStatic(cm.getModifiers())?0:1;
        for (int i=0,length=cm.getParameterTypes().length;i<length;i++){
            map.put(attr.variableName(i+pos),args[i]);
        }
        return map;
    }
}
